package store.lunangangster.engine.impl.agenda;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import store.lunangangster.bpmn.model.FlowElement;
import store.lunangangster.bpmn.model.FlowNode;
import store.lunangangster.bpmn.model.SequenceFlow;
import store.lunangangster.engine.NodeFlowException;
import store.lunangangster.engine.impl.bpmn.behavior.ModelBehavior;
import store.lunangangster.engine.impl.bpmn.behavior.ParallelGatewayBehavior;
import store.lunangangster.engine.impl.entity.ExecutionEntity;
import store.lunangangster.engine.impl.interceptor.CommandContext;

/**
 * 该操作会触发所持有的{@link ExecutionEntity}对象的当前{@link FlowElement}元素的相关行为。
 *
 * <ul>
 *   <li>对于{@link FlowNode}，执行其{@link FlowNode#getBehavior()}</li>
 *   <li>
 *     对于{@link SequenceFlow}，获取到{@link SequenceFlow#getTarget()}元素，再执行该元素对应的{@link DoElementBehaviorOperation}
 *   </li>
 * </ul>
 *
 * @author cwk
 * @version 1.0
 */
public class DoElementBehaviorOperation extends AbstractOperation {

  private static final Logger log = LoggerFactory.getLogger(DoElementBehaviorOperation.class);

  // 主要用于ParallelGateway的同步判断，需要知晓信号是从哪个IncomingSequenceFlow到来的
  protected FlowElement previousElement;

  public DoElementBehaviorOperation(ExecutionEntity execution, FlowElement previousElement,
      CommandContext commandContext) {
    super(execution, commandContext);
    this.previousElement = previousElement;
  }

  @Override
  public ExecutionEntity getExecution() {
    return execution;
  }

  @Override
  public void run() {
    FlowElement currentFlowElement = execution.getCurrentFlowElement();
    if (currentFlowElement instanceof SequenceFlow) {
      continueSequenceFlow((SequenceFlow) currentFlowElement);
    } else if (currentFlowElement instanceof FlowNode) {
      continueFlowNode((FlowNode) currentFlowElement);
    } else {
      throw new NodeFlowException("一个不正确的FlowElement被应用于ContinueProcessOperation: " + currentFlowElement);
    }
    // add to history
    commandContext.getProcessEngineConfiguration().getHistoryManager()
        .createNewHistory(execution, currentFlowElement);
  }

  protected void continueSequenceFlow(SequenceFlow sequenceFlow) {
    FlowNode target = sequenceFlow.getTarget();
    // 标记下一个即将到达的元素
    execution.setCurrentFlowElement(target);
    execution.setScope(false);
    // 执行该元素的behavior
    getAgenda().addDoElementBehaviorOperation(execution, sequenceFlow);
  }

  protected void continueFlowNode(FlowNode flowNode) {
    // TODO need Asynchronous
    executeSynchronous(flowNode);
  }

  protected void executeSynchronous(FlowNode flowNode) {
    // no need to check
    ModelBehavior behavior = (ModelBehavior) flowNode.getBehavior();
    // do behavior if existed, else go out from OutGoingSequenceFlow
    if (behavior != null) {
      setPreviousElementOnBehavior(previousElement, behavior, flowNode);
      behavior.doBehavior(execution);

    } else {
      // 虽然在FlowNodeBehavior中定义了默认的behavior，这里是为了兼容有些flowNode的behavior == null的情况
      getAgenda().addTakeOutGoingSequenceFlowOperation(execution);
    }
  }

  private void setPreviousElementOnBehavior(FlowElement previousElement, ModelBehavior behavior, FlowNode flowNode) {
    if (behavior instanceof ParallelGatewayBehavior) {
      boolean registerSuccess = ((ParallelGatewayBehavior) behavior).registerIncoming(
          (SequenceFlow) previousElement);
      if (registerSuccess) {
        String previousName = previousElement.getName() == null ? previousElement.getId() : previousElement.getName();
        String gatewayName = flowNode.getName() == null ? flowNode.getId() : flowNode.getName();
        log.debug("{}输入到同步网关:{}", previousName, gatewayName);
      }
    }
  }

}
